#include "unity.h"
#include "auth_service.h"
#include "user_repository.h"
#include "session_repository.h"
#include "database_manager.h"
#include <iostream>
#include <thread>
#include <chrono>

// Global pointers for testing - will be initialized in setUp
static DatabaseManager* dbManager = nullptr;
static UserRepository* userRepository = nullptr;
static SessionRepository* sessionRepository = nullptr;
static AuthService* authService = nullptr;

// Test result flags
static bool login_callback_called = false;
static bool register_callback_called = false;
static bool logout_callback_called = false;
static bool session_check_callback_called = false;

void setUp(void)
{
    // This is run before EACH test
    // Create a unique database file for this test
    static int test_counter = 0;
    std::string db_path = "data/test_async_auth_" + std::to_string(++test_counter) + ".db";
    
    // Create data directory if it doesn't exist
    system("mkdir -p data");
    
    // Initialize database manager with unique database file
    dbManager = new DatabaseManager(db_path);
    userRepository = new UserRepository(dbManager->getDatabaseConnection());
    sessionRepository = new SessionRepository(dbManager->getDatabaseConnection());
    authService = new AuthService(*userRepository, *sessionRepository);
    
    // Initialize database
    dbManager->initialize();
    
    // Reset test result flags
    login_callback_called = false;
    register_callback_called = false;
    logout_callback_called = false;
    session_check_callback_called = false;
    
    std::cout << "Test environment initialized" << std::endl;
}

void tearDown(void)
{
    // This is run after EACH test
    // Clean up allocated memory
    delete authService;
    delete sessionRepository;
    delete userRepository;
    delete dbManager;
    
    // Remove the test database file
    system("rm -f data/test_async_auth_*.db");
}

// Test async login functionality
void test_async_login(void)
{
    // Register a user first
    authService->registerAsync("testuser", "testpass", [](const RegistrationResult& result) {
        TEST_ASSERT_TRUE(result.success);
        register_callback_called = true;
    });
    
    // Wait a bit for registration to complete
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    
    // Now test login
    authService->loginAsync("testuser", "testpass", [](const LoginResult& result) {
        TEST_ASSERT_TRUE(result.success);
        TEST_ASSERT_EQUAL_STRING("登录成功", result.message.c_str());
        login_callback_called = true;
    });
    
    // Wait for login to complete
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    
    // Verify callbacks were called
    TEST_ASSERT_TRUE(register_callback_called);
    TEST_ASSERT_TRUE(login_callback_called);
}

// Test async logout functionality
void test_async_logout(void)
{
    // Register a user first
    authService->registerAsync("testuser", "testpass", [](const RegistrationResult& result) {
        TEST_ASSERT_TRUE(result.success);
        register_callback_called = true;
    });
    
    // Wait a bit for registration to complete
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    
    // Login
    authService->loginAsync("testuser", "testpass", [](const LoginResult& result) {
        TEST_ASSERT_TRUE(result.success);
        login_callback_called = true;
    });
    
    // Wait for login to complete
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    
    // Test logout (we'll use user ID 1 as that should be the first user)
    authService->logoutAsync(1, [](const LogoutResult& result) {
        TEST_ASSERT_TRUE(result.success);
        TEST_ASSERT_EQUAL_STRING("登出成功", result.message.c_str());
        logout_callback_called = true;
    });
    
    // Wait for logout to complete
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    
    // Verify callbacks were called
    TEST_ASSERT_TRUE(register_callback_called);
    TEST_ASSERT_TRUE(login_callback_called);
    TEST_ASSERT_TRUE(logout_callback_called);
}

int main(void)
{
    UNITY_BEGIN();
    RUN_TEST(test_async_login);
    RUN_TEST(test_async_logout);
    return UNITY_END();
}